﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using System.Runtime.Remoting;
using Lucene.Net.Store;

namespace CommonSearchModule
{
    public class Search
    {
        private string _IndexPath;
        private QueryTerm _Term;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="indexPath">索引文件路径</param>
        /// <param name="term">参数列表</param>
        public Search(string indexPath, QueryTerm term)
        {
            _IndexPath = indexPath;
            _Term = term;
        }

        public SearchResult GetSearchResult()
        {
            IndexSearcher searcher = new IndexSearcher(_IndexPath);
            SearchResult result = new SearchResult();
            StandardAnalyzer analyzer = new StandardAnalyzer();
            Stopwatch watch = new Stopwatch();
            try
            {
                Hits hits = null;
                Query query = GetQuery();
                watch.Start();
                if (query == null)
                {
                    query = new QueryParser(FieldKeys.SearchKey, analyzer).Parse("key");
                }
                #region 排序
                //Sort sort = new Sort("ID"); //排序依据
                //string[] sortOrder = { "ID", "Name" }; //多字段排序
                //Sort sort = new Sort("ID", true); //倒序排序\
                //SortField[] sortorder = { new SortField("ID"), new SortField("Name", true) }; Sort sort = new Sort(sortorder); //按ID的asc而name为desc方式排序

                Sort sort;//排序需要指定被排序的类型，默认是int
                switch (_Term.SortBy)
                {
                    case (int)SortBy.PackageTime:
                        sort = new Sort((new SortField("PackageTime", SortField.DOUBLE, false)));
                        break;
                    case (int)SortBy.ProductPrice_Asc:
                        sort = new Sort((new SortField("Price", SortField.DOUBLE, false)));
                        break;
                    case (int)SortBy.ProductPrice_Desc:
                        sort = new Sort((new SortField("Price", SortField.DOUBLE, true)));
                        break;
                    default:
                        sort = new Sort(new SortField("PrimaryKey", SortField.STRING, false));
                        break;
                }


                #endregion
                hits = searcher.Search(query, sort);
                watch.Stop();
                result.Result = GetResult(hits);
                result.RunTime = watch.Elapsed;
                result.Total = hits.Length();
            }
            finally
            {
                searcher.Close();
            }
            return result;
        }

        private List<Search_Entity> GetResult(Hits hits)
        {
            int start = (_Term.PageIndex - 1) * _Term.PageSize;
            int end = _Term.PageIndex * _Term.PageSize < hits.Length() ? _Term.PageIndex * _Term.PageSize : hits.Length();

            List<Search_Entity> lists = new List<Search_Entity>();
            for (int i = start; i < end; i++)
            {
                Document doc = new Document();
                doc = hits.Doc(i);
                Search_Entity view = new Search_Entity();
                view.PrimaryKey = doc.Get(FieldKeys.PrimaryKey);
                view.ID = doc.Get(FieldKeys.ID);
                view.Name = string.IsNullOrWhiteSpace(doc.Get(FieldKeys.Name)) ? doc.Get(FieldKeys.Name) : SetHighLighter(_Term.KeyWord, doc.Get(FieldKeys.Name));
                view.Info = string.IsNullOrWhiteSpace(doc.Get(FieldKeys.Info)) ? doc.Get(FieldKeys.Info) : SetHighLighter(_Term.KeyWord, doc.Get(FieldKeys.Info));
                view.CategoryName = string.IsNullOrWhiteSpace(doc.Get(FieldKeys.CategoryName)) ? doc.Get(FieldKeys.CategoryName) : SetHighLighter(_Term.KeyWord, doc.Get(FieldKeys.CategoryName));
                view.PackageTime = string.IsNullOrWhiteSpace(doc.Get(FieldKeys.PackageTime)) ? doc.Get(FieldKeys.PackageTime) : SetHighLighter(_Term.KeyWord, doc.Get(FieldKeys.PackageTime));
                view.PropertyName = string.IsNullOrWhiteSpace(doc.Get(FieldKeys.PropertyName)) ? doc.Get(FieldKeys.PropertyName) : SetHighLighter(_Term.KeyWord, doc.Get(FieldKeys.PropertyName));
                view.Price = Convert.ToDouble(doc.Get(FieldKeys.Price));
                view.ExtentionField1 = string.IsNullOrWhiteSpace(doc.Get(FieldKeys.ExtentionField1)) ? doc.Get(FieldKeys.ExtentionField1) : SetHighLighter(_Term.KeyWord, doc.Get(FieldKeys.ExtentionField1));

                view.ExtentionField2 = string.IsNullOrWhiteSpace(doc.Get(FieldKeys.ExtentionField2)) ? doc.Get(FieldKeys.ExtentionField2) : SetHighLighter(_Term.KeyWord, doc.Get(FieldKeys.ExtentionField2));

                view.ExtentionField3 = string.IsNullOrWhiteSpace(doc.Get(FieldKeys.ExtentionField3)) ? doc.Get(FieldKeys.ExtentionField3) : SetHighLighter(_Term.KeyWord, doc.Get(FieldKeys.ExtentionField3));

                view.ExtentionField4 = string.IsNullOrWhiteSpace(doc.Get(FieldKeys.ExtentionField4)) ? doc.Get(FieldKeys.ExtentionField4) : SetHighLighter(_Term.KeyWord, doc.Get(FieldKeys.ExtentionField4));

                view.ExtentionField5 = string.IsNullOrWhiteSpace(doc.Get(FieldKeys.ExtentionField5)) ? doc.Get(FieldKeys.ExtentionField5) : SetHighLighter(_Term.KeyWord, doc.Get(FieldKeys.ExtentionField5));
                view.SearchUrlType = doc.Get(FieldKeys.SearchUrlType);
                lists.Add(view);
            }
            return lists;
        }

        private string SetHighLighter(string keyword, string text)
        {
            string startTag = "{starttag}";
            string endTag = "{endtag}";

            if (string.IsNullOrEmpty(keyword)) return text;
            //关键字中英文拆分
            keyword = GetFields(keyword);
            string[] strs = keyword.Split(' ');

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < strs.Length; i++)
            {

                int _Kindex = text.ToLower().IndexOf(strs[i].ToLower());

                if (_Kindex != -1)
                {
                    string replaceKW = text.Substring(_Kindex, strs[i].Length);
                    text = Regex.Replace(text, replaceKW, string.Format("{0}{1}{2}", startTag, replaceKW, endTag), RegexOptions.IgnoreCase);
                }
            }
            text = text.Replace(startTag, "<font color=\"#C60A00\">").Replace(endTag, "</font>");
            return text;
        }
        /// <summary>
        /// 去除连续的空格
        /// </summary>
        /// <param name="strWords"></param>
        /// <returns></returns>
        private string GetFields(string strWords)
        {

            Regex replaceSpace = new Regex(@"\s{2,}", RegexOptions.IgnoreCase);

            return replaceSpace.Replace(strWords, " ").Trim();

        }
        private Query GetQuery()
        {
            if (_Term.IsNullQuery()) return null;
            Query query = null;
            StandardAnalyzer analyzer = new StandardAnalyzer();
            BooleanQuery bquery = new BooleanQuery();
            #region 关键字匹配方式
            if (!string.IsNullOrWhiteSpace(_Term.KeyWord))
            {
                //关键字中英文拆分
                string strKW = _Term.KeyWord;
                MultiFieldQueryParser mqp = new MultiFieldQueryParser(SearchConfig.KeywordFields, analyzer);
                mqp.SetDefaultOperator(QueryParser.Operator.OR);//几个字段之间用and 还是 or 
                strKW = GetFields(strKW);
                if (strKW.IndexOf(' ') != -1) strKW = strKW.Replace(" ", " AND ");//几个参数之间
                query = mqp.Parse(strKW);
                bquery.Add(query, BooleanClause.Occur.MUST);
            }
            if (!string.IsNullOrWhiteSpace(_Term.CategoryName))
            {
                //分类
                MultiFieldQueryParser mqp = new MultiFieldQueryParser(SearchConfig.CategoryNameFields, analyzer);
                query = mqp.Parse(_Term.CategoryName);
                bquery.Add(query, BooleanClause.Occur.MUST);
            }
            if (!string.IsNullOrWhiteSpace(_Term.PropertyName))
            {
                //属性
                string strProperty = _Term.PropertyName;
                MultiFieldQueryParser mqp = new MultiFieldQueryParser(SearchConfig.PropertyNameFields, analyzer);
                //mqp.SetDefaultOperator(QueryParser.Operator.OR); 
                //if (strProperty.IndexOf('|') != -1) strProperty = strProperty.Replace("|", " AND ").Trim();
                //if (strProperty.EndsWith("AND"))
                //    strProperty = strProperty.Substring(0, strProperty.Length - 3);
                strProperty.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries).ToList().ForEach(i =>
                {
                    query = mqp.Parse(i);
                    bquery.Add(query, BooleanClause.Occur.MUST);//SHOULD表示或
                });

            }

            if (!string.IsNullOrWhiteSpace(_Term.MinPrice) || !string.IsNullOrEmpty(_Term.MaxPrice))
            {
                double _minPrice, _maxPrice;
                if (!double.TryParse(_Term.MinPrice, out _minPrice))
                    _minPrice = 0d;
                if (!double.TryParse(_Term.MaxPrice, out _maxPrice) || _maxPrice == 0)
                    _maxPrice = double.MaxValue;

                query = NumericRangeQuery.NewDoubleRange(FieldKeys.Price, _minPrice, _maxPrice, true, true);
                bquery.Add(query, BooleanClause.Occur.MUST);
            }

            if (!string.IsNullOrWhiteSpace(_Term.SearchUrlType))
            {
                MultiFieldQueryParser mqp = new MultiFieldQueryParser(new string[] { FieldKeys.SearchUrlType }, analyzer);
                query = mqp.Parse(_Term.SearchUrlType);
                bquery.Add(query, BooleanClause.Occur.MUST);
            }
            #endregion
            return bquery;
        }
    }
}